home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / rs232.exe / RS232.DOC < prev   
Encoding:
Text File  |  1993-05-03  |  45.9 KB  |  1,083 lines

  1.  
  2.  
  3.  
  4.                           RS232.C User Documentation
  5.                           copyright C. Karcher 1992,93
  6.  
  7.  
  8.  
  9. >   About RS232.C:
  10.  
  11.     RS232.C was written to provide all of the basic functionality needed
  12.     to employ serial I/O in any application written with Borland 'C'
  13.     language compilers.  Some features are:
  14.  
  15.     1. Ease of use.  No assembly language or library files are used and a
  16.     simple "#include" statement is all that is required to access all of
  17.     the functions provided.
  18.  
  19.     2. Both input and output are buffered and interrupt driven for
  20.     efficiency.
  21.  
  22.     3. Serial ports 1 - 4 are supported on PC, AT and PS/2 compatibles.
  23.     Chained interrupts used on port 3 and 4 are allowed for so as not to
  24.     interfere with devices such as a mouse or printer.  Transmission
  25.     speeds of 110 to 115200 baud are available.
  26.  
  27.     4. Detection and utilization of hardware buffered UARTs (NS16550AF
  28.     etc.) found in some machines is automatic.
  29.  
  30.     5. Interrupt driven hardware and XON/XOFF flow control is provided for.
  31.  
  32.     6. All source code is included.  RS232.C can be used with all memory
  33.     models.
  34.  
  35.  
  36.     This is user supported software and may be distributed freely in a
  37.     whole and unmodified state.  It may be used in part or wholly, free of
  38.     royalty, to develop any commercial applications provided that the
  39.     developer has registered RS232.C.  Registration entitles the developer
  40.     to any future enhancements or upgrades which may be released.
  41.     Registration also includes technical support as far as can be provided
  42.     via mail, telephone or electronic messaging.  To register RS232.C,
  43.     send a check or money order for $20.00 to:
  44.  
  45.          Chris A. Karcher
  46.          9537 Evanston Ave. N.
  47.          Seattle WA 98103-3131
  48.  
  49.     The author may be contacted by mail at the above address, by telephone
  50.     at (206)789-7945 or via Compuserve EMAIL to user ID 76406,536.
  51.  
  52.     The author of RS232.C makes no expressed or implied warranty of any
  53.     kind with regard to the software or accompanying documentation.  In no
  54.     event shall the author be held liable for incidental or consequential
  55.     damages in connection or arising out of performance or use of any part
  56.     of this software.
  57.  
  58.     The distribution should include the following files:
  59.  
  60.         RS232.C   - serial communication routines source code
  61.         RS232.DOC - documentation (this file)
  62.         RS_DEMO.C - sample program demonstrating RS232.C
  63.  
  64. >   Why use RS232.C?
  65.  
  66.     Borland's C compilers (and probably all DOS based C compilers) do
  67.     provide some basic support for serial communications but that support
  68.     makes use of calls to BIOS routines only.  The BIOS serial routines
  69.     are adequate only for the slowest of transmission speeds and do not
  70.     exploit all of the capabilities of the hardware found in PC's.  If
  71.     efficient serial communication is required, the programmer must
  72.     provide all of the low level software.  RS232.C does just that by
  73.     taking care of all the low level details and providing the programmer
  74.     with all the high level functions needed for efficient serial I/O.
  75.  
  76. >   How to use RS232.C:
  77.  
  78.     All that is required to use RS232.C is to include it in your source
  79.     code.  The simplest way to do that is with a compiler '#include'
  80.     directive, treating RS232.C just as you would a header file.  Having
  81.     done that, three basic steps are all that are required to perform
  82.     serial I/0:
  83.  
  84.          1. Allocate memory for input and output buffers.  (It can be pre-
  85.          allocated at compile time or allocated via some memory
  86.          allocation function like malloc at runtime.)
  87.  
  88.          2. "Open" the port with the function rs_initport, using the
  89.          desired communication parameters.
  90.  
  91.              perform I/O with functions provided
  92.                 .     .    .      .        .
  93.                 .     .    .      .        .
  94.                 .     .    .      .        .
  95.  
  96.          3. "Close" the port when finished performing I/O with the
  97.          function rs_close before ending the program.
  98.  
  99.     The file RS_DEMO.C, included with the distribution, is a sample
  100.     terminal program demonstrating most of the functions available with
  101.     RS232.C.
  102.  
  103.     The following code demonstrates an extremely simple but functional
  104.     program which turns a PC into a dumb terminal capable of communicating
  105.     with a modem or another computer:
  106.  
  107.      /*
  108.        TERM: a light weight dumb terminal program to demonstrate rs232.c
  109.        C. Karcher
  110.      */
  111.  
  112.     #include<conio.h>
  113.     #include"src\rs232.c"       /* include rs232 variables and functions */
  114.  
  115.     main()
  116.     {
  117.  
  118.        int key = 0;
  119.        char input_buffer[1024],output_buffer[1024]; /* allocate buffers */
  120.  
  121.        /* open COM port 1 with 2400 baud, no parity, 8 data bits, 1 stop bit,
  122.           a 1024 byte input buffer and a 1024 byte output buffer */
  123.  
  124.        if(rs_initport(RS_PORT1,RS_B2400,RS_NOPAR,RS_DBIT8,RS_SBIT1,
  125.                              1024U,input_buffer,1024U,output_buffer) > 0)
  126.          cprintf("Terminal mode active - press escape to exit\r\n");
  127.        else{
  128.          cprintf("Unable to open COM port\r\n");
  129.          return 0;
  130.          }
  131.  
  132.       /* turn on Data Terminal Ready */
  133.       rs_modctrl(RS_WRTMCR,RS_MCRDTR,RS_LINON);
  134.  
  135.       /* display any characters received and send any keystrokes typed until
  136.          escape is pressed */
  137.       do{
  138.         if(rs_inrcvd())                 /* if a character has been received */
  139.           putch(rs_getbyt());           /*    display it */
  140.         if(rs_keyhit())                 /* if a key has been pressed */
  141.           rs_sndbyt((key = getch()));   /*    send it */
  142.         }while(key != 27);              /* if the key pressed was ESC, end */
  143.  
  144.       /* turn off Data Terminal Ready */
  145.       rs_modctrl(RS_WRTMCR,RS_MCRDTR,RS_LINOFF);
  146.  
  147.       /* close the port and exit */
  148.       rs_close();
  149.       return 0;
  150.  
  151.     } /* end TERM */
  152.  
  153. >   RS232.C Functions:
  154.  
  155.     The following is a list of the functions contained in RS232.C and a
  156.     brief explanation of the purpose of each one.  A detailed description
  157.     of each function and it's use follows:
  158.  
  159.     rs_initport - Prepares a COM port for use.
  160.     rs_sndbyt   - Sends a single byte.
  161.     rs_sndstr   - Sends a string of bytes.
  162.     rs_getbyt   - Gets a single byte.
  163.     rs_getstr   - Gets a string of bytes.
  164.     rs_inrcvd   - Returns number of bytes which been received.
  165.     rs_outfre   - Returns amount of free space remaining in output buffer.
  166.     rs_error    - Returns code for last error detected.
  167.     rs_modctrl  - Controls or returns status of modem control lines.
  168.     rs_break    - Sends break to remote equipment.
  169.     rs_clrout   - Clears output buffer.
  170.     rs_clrin    - Clears input buffer.
  171.     rs_keyhit   - Determines if a key has been pressed.
  172.     rs_timer    - Times events or operations.
  173.     rs_setflow  - Establishes or returns status of flow control.
  174.     rs_close    - "Closes" port prepared by rs_initport.
  175.  
  176. >   Function Reference: (Note: The pre defined constants shown in
  177.                          parentheses with some of the function argument
  178.                          descriptions or return value descriptions are
  179.                          defined in RS232.C and may be used for
  180.                          convenience.)
  181.  
  182.   >   rs_initport:
  183.  
  184.     >   Purpose:
  185.           Prepares a COM port for use.
  186.  
  187.     >   Prototype:
  188.           int rs_initport(char port, long baud, char parity, char data_bits,
  189.                          char stop_bits, unsigned in_buf_size, char *in_buf,
  190.                          unsigned out_buf_size, char *out_buf);
  191.  
  192.     >   Arguments:
  193.            port: Character indicating which port to use.  May be one of
  194.                  the following:
  195.                    '1' (RS_PORT1) - COM port 1
  196.                    '2' (RS_PORT2)
  197.                    '3' (RS_PORT3)
  198.                    '4' (RS_PORT4) - COM port 4
  199.            baud: The long value indicating the baud rate.  Can be any of
  200.                  the following:
  201.                    110L (RS_B110) - 110 baud
  202.                    300L (RS_B300)
  203.                    600L (RS_B600)
  204.                    1200L (RS_B1200)
  205.                    2400L (RS_B2400)
  206.                    4800L (RS_B4800)
  207.                    9600L (RS_B9600)
  208.                    19200L (RS_B19K)
  209.                    38400L (RS_B38K)
  210.                    57600L (RS_B57K)
  211.                    115200L (RS_B115K) - 115200 baud
  212.          parity: A character indicating the type of parity checking to use
  213.                  as follows:
  214.                    'N' (RS_NOPAR) - no parity
  215.                    'E' (RS_EVPAR) - even parity
  216.                    'O' (RS_ODPAR) - odd parity
  217.                    'S' (RS_SPPAR) - parity bit always space
  218.                    'M' (RS_MKPAR) - parity bit always mark
  219.       data_bits: A character indicating how many data bits to use in each
  220.                  byte:
  221.                    '8' (RS_DBIT8) - 8 data bits
  222.                    '7' (RS_DBIT7) - 7 data bits
  223.       stop_bits: A character indicating the number of stop bits to use:
  224.                    '1' (RS_SBIT1) - 1 stop bit
  225.                    '2' (RS_SBIT2) - 2 stop bits
  226.      in_buf_siz: An unsigned integer between 2 and 32768 indicating the
  227.                  size in bytes of the input buffer.  The value must be a
  228.                  power of 2 (i.e. 2,4,8,16,256,512,1024 etc.).
  229.          in_buf: Character pointer to the input buffer allocated by the
  230.                  application.
  231.     out_buf_siz: The unsigned value between 2 and 32768 indicating the
  232.                  size in bytes of the output buffer.  The value must be a
  233.                  power of 2 (i.e. 2,4,8,16,256,512,1024 etc.).
  234.         out_buf: Character pointer to the output buffer.
  235.  
  236.          Note: If RS_POLLED_XMIT is defined, the output buffer is not used
  237.          for serial output.  In this case the output buffer size may be 0
  238.          and the output buffer pointer may be NULL.
  239.  
  240.     >    Return value:
  241.            rs_initport can return the following integer values indicating
  242.            the success or failure of the operation:
  243.              4 (RS_UART4) Success, UART detected was a 16550 capable of
  244.                hardware buffering.  This capability is automatically
  245.                utilized.
  246.              3 (RS_UART3) Success, UART detected was a 16550 incapable of
  247.                hardware buffering.
  248.              2 (RS_UART2) Success, UART detected was an 8250A or 16450.
  249.              1 (RS_UART1) Success, UART detected was an 8250B
  250.              0 (RS_NOUART) Failure, no UART detected.
  251.             -1 (RS_BADIBUF) Failure, input buffer size invalid or input
  252.                buffer pointer is a NULL pointer.
  253.             -2 (RS_BADOBUF) Failure, output buffer size invalid or output
  254.                buffer pointer is a NULL pointer.
  255.             -3 (RS_BADPORT) Failure, invalid port argument.
  256.             -4 (RS_BADPAR) Failure, invalid parity argument.
  257.             -5 (RS_BADDBIT) Failure, invalid data_bits argument.
  258.             -6 (RS_BADSBIT) Failure, invalid stop_bits argument.
  259.             -7 (RS_BADBAUD) Failure, invalid baud argument.
  260.  
  261.     >    Examples:
  262.  
  263.            if(rs_initport(RS_PORT1,RS_B2400,RS_NOPAR,RS_DBIT8,RS_SBIT1,
  264.                           1024U,input_buffer,1024U,output_buffer) > 0)
  265.              cprintf("Terminal mode active - press escape to exit\r\n");
  266.  
  267.            port_ok = rs_initport(port,RS_B2400,RS_NOPAR,RS_DBIT8,RS_SBIT1,
  268.                                            BUF_SIZ,in_buf,BUF_SIZ,out_buf);
  269.  
  270.     >    Notes:
  271.  
  272.          If a port has already been "opened" with rs_initport, it will
  273.          automatically be closed before another port (or the same port) is
  274.          opened.  Only one port may be opened at any one time although the
  275.          interrupt service routine installed by rs_initport can coexist
  276.          with others sharing the same IRQ (interrupt request).  An example
  277.          of this would be serial mouse installed on COM port 1 and an
  278.          application using rs_initport to prepare access to COM port 3.
  279.          In this case, both the mouse driver and the application would be
  280.          using IRQ4.  Some serial applications "take over" the interrupt
  281.          completely which would disable use of the mouse.  The interrupt
  282.          service routine installed by rs_initport "chains" the interrupt
  283.          so that if it is invoked by other than the targeted device,
  284.          control is passed to the appropriate routine.
  285.  
  286.          To determine the appropriate I/O address for a given COM port's
  287.          UART, rs_initport first uses the BIOS data area and, failing
  288.          this, uses the "standard" I/O addresses.  Standard IRQ's are also
  289.          assumed.  If a serial adapter has been installed with other than
  290.          the standard I/O addresses and IRQ's, rs_initport will not find
  291.          the UART and will fail.  The standard addresses and IRQ's assumed
  292.          are:
  293.               port          I/O address            IRQ
  294.               COM1          3F8                    4
  295.               COM2          2F8                    3
  296.               COM3          3E8 (PS/2 = 3220)      4 (PS/2 = 3)
  297.               COM4          2E8 (PS/2 = 3228)      3 (PS/2 = 4)
  298.  
  299.          If a UART capable of FIFO buffering is detected, this feature is
  300.          automatically enabled.  This can greatly reduce the amount of
  301.          overhead due to interrupts and can prevent "lost characters" due
  302.          to receive overruns at higher transmission speeds.
  303.  
  304.          rs_initport does not alter the state of any of the modem control
  305.          output lines (DTR or RTS).  They must be explicitly controlled
  306.          using rs_modctrl.
  307.  
  308.  
  309.   >   rs_sndbyt
  310.     >   Purpose:
  311.           Sends a single byte.
  312.  
  313.     >   Prototype:
  314.           int rs_sndbyt(int rs_snd);
  315.  
  316.     >   Arguments:
  317.           The byte to send (int converted to char).
  318.  
  319.     >   Return Value:
  320.           Returns 0 if the byte was successfully written to the output
  321.           buffer.  Returns -1 no port open or byte could not be written.
  322.  
  323.     >   Examples:
  324.  
  325.         if(rs_sndbyt('A'))
  326.           printf("Unable to send message\n");
  327.  
  328.         rs_sndbyt(getche());
  329.  
  330.     >   Notes:
  331.           rs_sndbyt writes the character into the output buffer and
  332.           returns immediately without waiting for the character to
  333.           actually be transmitted.  If there is no room in the output
  334.           buffer, rs_sndbyt will wait until there is room unless output is
  335.           currently disabled via flow control.  In this case, rs_sndbyt
  336.           returns -1 to indicate failure.
  337.           If transmit interrupts are disabled by defining RS_POLLED_XMIT,
  338.           the buffer is not used and the character is sent when the UART
  339.           is free to send it.  If output is disabled via flow control,
  340.           the character is not sent and rs_sndbyt returns -1.
  341.  
  342.   >   rs_sndstr
  343.  
  344.     >   Purpose:
  345.           Sends a string of bytes.
  346.  
  347.     >   Prototype:
  348.           int rs_sndstr(int rs_sndcnt, char *rs_sndstr);
  349.  
  350.     >   Arguments:
  351.           rs_sndcnt indicates the number of bytes to be sent - if a number
  352.           other than 0 is specified, the string need not be nul
  353.           terminated.  If rs_sndcnt is 0, rs_sndstr is treated as a nul
  354.           terminated string and characters will be sent up to but not
  355.           including the terminating nul.  rs_sndstr is a character pointer
  356.           to the string to be sent.  rs_sndstr can be larger than the size
  357.           of the output buffer and up to 32767 bytes.
  358.  
  359.     >   Return Value:
  360.           Function returns 0 on success.  If no port is open, it returns
  361.           -1.  If the entire string could not be written to the output
  362.           buffer, the number of characters written is returned.
  363.  
  364.     >   Examples:
  365.  
  366.           rs_sndstr(0, "Hello, world.");
  367.  
  368.           if(rs_sndstr(strlen(msg),msg)
  369.             printf("Message could not be sent\n");
  370.  
  371.     >   Notes:
  372.           Like rs_sndbyt, rs_sndstr writes the characters to the output
  373.           buffer and returns immediately - it does not wait for the
  374.           characters to actually be transmitted.  If there is insufficient
  375.           room in the output buffer, it waits until there is unless output
  376.           is currently disabled via flow control.  In this case, rs_sndbyt
  377.           returns the number of characters that were written to the
  378.           buffer.
  379.           If transmit interrupts are disabled by defining RS_POLLED_XMIT,
  380.           the output buffer is not used and the function does not return
  381.           until the entire string has been sent or output becomes disabled
  382.           via flow control.
  383.  
  384.   >   rs_getbyt
  385.  
  386.     >   Purpose:
  387.           Gets a single byte.
  388.  
  389.     >   Prototype:
  390.           int rs_getbyt(void);
  391.  
  392.     >   Arguments:
  393.           none
  394.  
  395.     >   Return Value:
  396.           Returns the next received byte (converted to int) available.  If
  397.           no characters are currently waiting to be read from the input
  398.           buffer, returns -1.
  399.  
  400.     >   Examples:
  401.  
  402.           while(rs_inrcvd()
  403.             putch(rs_getbyt());
  404.  
  405.           if((ch = rs_getbyt()) < 0)
  406.             printf("No received character\n");
  407.  
  408.     >   Notes:
  409.           rs_getbyt does not wait for incoming characters - it returns -1
  410.           immediately if no received characters are available.
  411.  
  412.   >   rs_getstr
  413.  
  414.     >   Purpose:
  415.           Gets a string of bytes.
  416.  
  417.     >   Prototype:
  418.           int rs_getstr(int rs_getcnt, char *rs_getbuf);
  419.  
  420.     >   Arguments:
  421.           rs_getcnt is the number of characters to be read from the input
  422.           buffer.  If rs_getcnt is 0, characters are read from the input
  423.           buffer until a nul character is encountered, which is included
  424.           in rs_getbuf.  rs_getbuf is a character pointer to the string
  425.           which the received characters will be written in to.  rs_getbuf
  426.           must be large enough to hold the entire string plus a
  427.           terminating nul character.  rs_getstr can be used to get a
  428.           string up to the input buffer size.
  429.  
  430.     >   Return Value:
  431.           Returns -1 if no port is open or the number of characters read
  432.           from the input buffer and written to the target string.
  433.  
  434.     >   Examples:
  435.  
  436.           if(rs_getstr(8,msg) > 8)
  437.             printf("No message available\n");
  438.  
  439.     >   Notes:
  440.           If the requested number of characters are not available,
  441.           rs_getstr does not wait for them to become available but instead
  442.           copies as many as are available and returns the number copied.
  443.  
  444.   >   rs_inrcvd
  445.  
  446.     >   Purpose:
  447.           Returns number of bytes which been received.
  448.  
  449.     >   Prototype:
  450.           unsigned rs_inrcvd(void);
  451.  
  452.     >   Arguments:
  453.           none
  454.  
  455.     >   Return Value:
  456.           Returns the number of characters which have been received and
  457.           are ready to be read from the input buffer by rs_getbyt or
  458.           rs_getstr.
  459.  
  460.     >   Examples:
  461.  
  462.           in_cnt = rs_inrcvd();
  463.  
  464.           rs_getstr(rs_inrcvd(),msg);
  465.  
  466.     >   Notes:
  467.           rs_inrcvd will never return a value greater than the input
  468.           buffer size specified when rs_initport was called, even if an
  469.           input buffer overflow has occurred.  Use rs_error to determine
  470.           if there has been an overflow.
  471.  
  472.   >   rs_outfre
  473.  
  474.     >   Purpose:
  475.           Returns amount of free space remaining in output buffer.  If
  476.           RS_POLLED_XMIT is defined, this function will not return a
  477.           meaningful value.
  478.  
  479.     >   Prototype:
  480.           unsigned rs_outfre(void);
  481.  
  482.     >   Arguments:
  483.           none
  484.  
  485.     >   Return Value:
  486.           Unsigned integer indicating current amount of free space in
  487.           bytes that are available in the output buffer.
  488.  
  489.     >   Examples:
  490.  
  491.           if(rs_outfre() == 0)
  492.             printf("Serial port busy - try again later\n");
  493.  
  494.           printf("%u bytes are currently buffered for output\n",
  495.                      output_buffer_size - rs_outfre());
  496.  
  497.   >   rs_error
  498.  
  499.     >   Purpose:
  500.           Returns code for last error detected.
  501.  
  502.     >   Prototype:
  503.           int rs_error(void);
  504.  
  505.     >   Arguments:
  506.           none
  507.  
  508.     >   Return Value:
  509.           Returns integer whose bit pattern indicates the last error which
  510.           occurred as follows:
  511.             bit 0 (RS_RBER): 1 = receive buffer overflow
  512.             bit 1 (RS_ROER): 1 = receive data overrun (UART received data
  513.                              faster than it could be read by the interrupt
  514.                              service routine)
  515.             bit 2 (RS_PERR): 1 = parity error
  516.             bit 3 (RS_FERR): 1 = framing error
  517.             bit 4 (RS_BKDT): 1 = break detected
  518.           Returns 0 if no error has been detected since last call to
  519.           rs_error or since port was opened.
  520.  
  521.     >   Examples:
  522.  
  523.           if(rs_error())
  524.             printf("Serial port error\n");
  525.  
  526.           if(rs_error() & RS_PERR)
  527.             printf("Parity error!\n");
  528.  
  529.     >   Notes:
  530.           A call to rs_error returns a code for any errors which have
  531.           occurred and clears the error flags.  Subsequent calls will not
  532.           indicate the same error unless it has reoccurred.
  533.  
  534.           Most UARTs will indicate a framing error when a break is
  535.           detected.
  536.  
  537.   >   rs_modctrl
  538.  
  539.     >   Purpose:
  540.           Controls or returns status of modem control lines.
  541.  
  542.     >   Prototype:
  543.           int rs_modctrl(int rs_cmd,...);
  544.  
  545.     >   Arguments:
  546.           rs_cmd = 2 (RS_GETMCR): Return status of modem control output
  547.                                   lines.
  548.           rs_cmd = 1 (RS_WRTMCR): Change status of modem control output
  549.                      lines.  2 additional arguments are required with this
  550.                      command. The first is an integer with a bit pattern
  551.                      indicating which line(s) to control:
  552.                         1 (RS_MCRDTR): Data Terminal Ready line.
  553.                         2 (RS_MCRRTS): Ready To Send line.
  554.                      The second is an integer determining whether the
  555.                      line(s) should be turned on or off:
  556.                         0 (RS_LINOFF): Turn line off.
  557.                         1 (RS_LINON): Turn line on.
  558.           rs_cmd = 0 (RS_GETMSR): Return status of modem control input
  559.                      lines.
  560.  
  561.     >   Return Value:
  562.           If rs_cmd = 0 (RS_GETMSR), an integer with a bit pattern
  563.           indicating the requested status is returned:
  564.             0x01 (RS_CTSCHG) CTS line changed states
  565.             0x02 (RS_DSRCHG) DSR line changed states
  566.             0x04 (RS_RICHG)  RI line changed states
  567.             0x08 (RS_DCDCHG) DCD line changed states
  568.             0x10 (RS_CTSSTE) state of CTS line
  569.             0x20 (RS_DSRSTE) state of DSR line
  570.             0x40 (RS_RICHG)  state of RI line
  571.             0x80 (RS_DCDCHG) state of DCD line
  572.           If rs_cmd = 1 (RS_WRTMCR), zero is returned.
  573.           If rs_cmd = 2 (RS_GETMCR), an integer with a bit pattern
  574.           indicating the current state of the modem control output lines
  575.           is returned:
  576.             0x01 (RS_MCRDTR): 1 = DTR on
  577.             0x02 (RS_MCRRTS): 1 = RTS on
  578.           If an operation fails (no port open), -1 is returned.
  579.  
  580.     >   Examples:
  581.  
  582.           if(! (rs_modctrl(RS_GETMSR) & RS_MSRDSR))
  583.             printf("Remote equipment is not ready\n");
  584.  
  585.           /* set Data Terminal Ready output line on */
  586.           rs_modctrl(RS_WRTMCR,RS_MCRDTR,RS_LINON);
  587.  
  588.           if(rs_modctrl(RS_GETMCR) & RS_MCRRTS)
  589.             printf("Ready To Send output line is currently off\n");
  590.  
  591.     >   Notes:
  592.           When using rs_modctrl to return the status of the modem status
  593.           input lines (rs_cmd = RS_GETMSR), the lower 4 bits of the value
  594.           returned indicate that the corresponding modem status lines have
  595.           changed states since the last time the status was read.
  596.           The next time the status is read, these bits will be cleared
  597.           unless a line has again changed states.
  598.  
  599.           When using rs_modctrl to set modem control output lines, more
  600.           than 1 line can be turned on or off with the same call by or'ing
  601.           the bit pattern for the desired lines (i.e.
  602.           rs_modctrl(WRTMCR,RS_MCRDTR | RS_MCRRTS,RS_LINON) ).
  603.  
  604.   >   rs_break
  605.  
  606.     >   Purpose:
  607.           Sends break to remote equipment.
  608.  
  609.     >   Prototype:
  610.           int rs_break(void);
  611.  
  612.     >   Return Value:
  613.           Returns 0 on success, -1 if no port open.
  614.  
  615.     >   Examples:
  616.  
  617.           if(rs_error())
  618.             rs_break();
  619.  
  620.     >   Notes:
  621.           An RS232 line is normally in the "marking" state when idle.
  622.           rs_break places the line in a spacing state for approx. 1
  623.           character period.  It is used by some communications equipment
  624.           to signal some event.
  625.  
  626.           If a buffer transmit is currently in progress, rs_break will
  627.           wait until the buffer is empty before sending the break unless
  628.           output is currently disabled via flow control.  In this case,
  629.           rs_break will send the break immediately.
  630.  
  631.   >   rs_clrout
  632.  
  633.     >   Purpose:
  634.           Clears output buffer (and the UART output FIFO if used).  If
  635.           RS_POLLED_XMIT is defined, clears the output FIFO only.
  636.  
  637.     >   Prototype:
  638.           void rs_clrout(void);
  639.  
  640.     >   Return Value:
  641.           none
  642.  
  643.     >   Examples:
  644.  
  645.           if(rs_error() & RS_BKDT)  /* break detected */
  646.             rs_clrout();            /*  stop transmission, clear output */
  647.  
  648.     >   Notes:
  649.           rs_clrout will immediately stop transmission and clear the
  650.           output buffer.  It has no effect if a port is not open.
  651.  
  652.   >   rs_clrin
  653.  
  654.     >   Purpose:
  655.           Clears input buffer.
  656.  
  657.     >   Prototype:
  658.           void rs_clrin(void);
  659.  
  660.     >   Return Value:
  661.           none
  662.  
  663.     >   Examples:
  664.  
  665.           if(rs_error()){ /* if an error occurred */
  666.             rs_clrin();   /*    clear input buffer */
  667.             rs_sndstr(0,"resend last message");
  668.             }
  669.  
  670.     >   Notes:
  671.           rs_clrin will immediately clear the input buffer of any
  672.           characters not yet read.  If a UART FIFO is in use, it will also
  673.           be cleared.
  674.  
  675.   >   rs_keyhit
  676.  
  677.     >   Purpose:
  678.           Determines if a key has been pressed.
  679.  
  680.     >   Prototype:
  681.           int rs_keyhit(void);
  682.  
  683.     >   Return Value:
  684.           Returns 0 if no keys have been pressed, 1 if one or more keys
  685.           have been pressed but not yet read.
  686.  
  687.     >   Examples:
  688.  
  689.           if(rs_keyhit())
  690.             rs_sndbyt(getch());
  691.  
  692.     >   Notes:
  693.           When constant keyboard monitoring is required, rs_keyhit should
  694.           be used in place of library functions like kbhit().  rs_keyhit
  695.           reads the BIOS keyboard data area directly to determine if any
  696.           keys have been pressed.  Library functions like kbhit() call a
  697.           BIOS interrupt routine to accomplish the same thing.  This can
  698.           cause loss of incoming serial data when using high transmission
  699.           speeds.  A port need not be open to use this function.
  700.  
  701.   >   rs_timer
  702.  
  703.     >   Purpose:
  704.           Times events or operations.
  705.  
  706.     >   Prototype:
  707.           unsigned rs_timer(int rs_cmd);
  708.  
  709.     >   Arguments:
  710.           One integer argument determines the action which will be taken:
  711.             0 (RS_CLRTIM): The current timer value is returned and the
  712.                            timer is set to 0.
  713.             1 (RS_GETTIM): The current timer value is returned and timing
  714.                            continues.
  715.  
  716.     >   Return Value:
  717.           rs_timer returns an unsigned integer indicating the number of
  718.           "ticks" (18.2 per second) which have elapsed.
  719.  
  720.     >   Examples:
  721.  
  722.           rs_timer(RS_CLRTIM);
  723.           rs_sndstr(msg_len,msg);
  724.           while(! rs_inrcvd()){
  725.             if(rs_timer(RS_GETTIM) > 18){ /* wait approx. 1 second */
  726.               printf("Message response timed out\n");
  727.               break;
  728.               }
  729.             }
  730.  
  731.     >   Notes:
  732.           rs_timer reads the BIOS time data area directly and avoids use
  733.           of BIOS interrupt calls to do this.  It should be used instead
  734.           of library routines such as biostime() to avoid loss of incoming
  735.           serial data when performing high speed communication.  The value
  736.           returned may be in error by as much as 1 "tick" so should be
  737.           considered a fairly low resolution timer.  A port need not be
  738.           open to use this function.
  739.  
  740.   >   rs_setflow
  741.  
  742.     >   Purpose:
  743.           Establishes or returns status of flow control.
  744.  
  745.     >   Prototype:
  746.           int rs_setflow(int rs_cmd,...);
  747.  
  748.     >   Arguments:
  749.           rs_cmd can be one of the following:
  750.             0 (RS_FLWOFF) -  Disables flow control.
  751.             1 (RS_FLWHDW) -  Enables hardware flow control.  Requires an
  752.                              additional integer argument to define hardware
  753.                              line(s) to use for flow control:
  754.                                1 (RS_FLWCTS) - Use Clear To Send
  755.                                2 (RS_FLWDSR) - Use Data Set Ready
  756.                                4 (RS_FLWRI) - Use Ring Indicator
  757.                                8 (RS_FLWDCD) - Use Data Carrier Detect
  758.             2 (RS_FLWXON) -  Enables XON/XOFF flow control.  Requires two
  759.                              additional parameters, the first of which
  760.                              defines the character to use for XON, the
  761.                              second defining the character to use as XOFF.
  762.                              The following two pre-defined constants are
  763.                              the standard XON and XOFF characters:
  764.                                0x11 (RS_XON)
  765.                                0x13 (RS_XOFF)
  766.             3 (RS_FLWSTAT) - Returns the status of flow control.  1
  767.                              indicates that output is currently disabled
  768.                              by flow control.  0 indicates output is
  769.                              currently enabled.
  770.             4 (RS_FLWINS)  - Inserts a control character in the output
  771.                              stream.  The control character to be sent is
  772.                              defined by one additional argument.
  773.  
  774.  
  775.     >   Return Value:
  776.           Returns -1 if no port open.  Except when rs_cmd is 3
  777.           (RS_FLWSTAT), returns 0 on success.  When rs_cmd is RS_FLWSTAT,
  778.           value returned is status of flow control.
  779.  
  780.     >   Examples:
  781.  
  782.           /* set flow control to use Data Set Ready hardware line */
  783.           rs_setflow(RS_FLWHDW,RS_FLWDSR);
  784.  
  785.           /* set flow control to XON/XOFF using standard XON and XOFF
  786.              characters */
  787.           rs_setflow(RS_FLWXON,RS_XON,RS_XOFF);
  788.  
  789.           if(rs_setflow(RS_FLWSTAT))
  790.             printf("Output currently disabled via flow control\n");
  791.  
  792.           /* send XOFF character to remote */
  793.           rs_setflow(RS_FLWINS,RS_XOFF);
  794.  
  795.           /* disable flow control */
  796.           rs_setflow(RS_FLWOFF);
  797.  
  798.     >   Notes:
  799.           Enabling flow control, whether with hardware line monitoring or
  800.           with XON/XOFF characters, will cause output to stop immediately
  801.           when the defined condition is met (the selected hardware line
  802.           goes to logic 0 or the character used as XOFF is received).  Any
  803.           characters buffered for output will remain buffered and
  804.           transmission will resume when the hardware line being used for
  805.           flow control goes to logic 1 or the character used for XON is
  806.           received.  Flow control effects output only.  Characters can
  807.           continue to be received or written to the output buffer up to
  808.           it's capacity when output is disabled via flow control.  Only
  809.           one type of flow control may be used at once.
  810.  
  811.           If the remote equipment is using XON/XOFF type flow control,
  812.           rs_setflow can be used to control remote output with the
  813.           RS_FLWINS command.  The control character will be sent
  814.           immediately, even if characters are already being transmitted
  815.           via the output buffer.  The buffer will continue to be sent
  816.           after the control character has been transmitted.
  817.  
  818.   >   rs_close
  819.  
  820.     >   Purpose:
  821.           Closes" port prepared by rs_initport.
  822.  
  823.     >   Prototype:
  824.           void rs_close(void);
  825.  
  826.     >   Return Value:
  827.           none
  828.  
  829.     >   Notes:
  830.           This function should always be used when an application has
  831.           "opened" a port with rs_initport.  rs_close disables interrupts
  832.           from the port and restores the previous interrupt vector.
  833.           Failure to call rs_close before exiting from the application can
  834.           very likely cause undefined behavior.  The function can be
  835.           registered with the library function atexit() to insure that it
  836.           gets called.  It is probably also a good idea to install a
  837.           ctrl-break handler which calls rs_close to prevent exiting the
  838.           application without closing the port:
  839.  
  840.             int c_break(void)
  841.             {
  842.               rs_close();
  843.               return(0);
  844.             }
  845.  
  846.               /* somewhere in application */
  847.               ctrlbrk(c_break); /* library function ctrlbrk registers
  848.                                    cleanup function */
  849.  
  850.           If a buffer transmit is currently in progress, rs_close waits
  851.           for it to finish before closing the port unless output is
  852.           currently disabled via flow control.
  853.  
  854. >   General Notes:
  855.  
  856.   >   Baud Rates:
  857.           Although RS232.C supports speeds up to 115.2K baud, the higher
  858.           speeds may not work on some machines due to a variety of
  859.           factors.  Foremost is the speed of the CPU itself - slower
  860.           machines may not be capable of sustained input at high speeds.
  861.           Other factors may effect the maximum usable baud rate also.  For
  862.           instance, even though a machine's CPU is fast enough to support
  863.           high speeds, other software running on the machine may prevent
  864.           it.  (One example is a 386 CPU running an extended memory
  865.           manager which places the CPU in protected mode.  This can cause
  866.           interrupt service routines to be slower.)  The BIOS in some
  867.           machines may have routines which are too slow, such as the timer
  868.           interrupt service routine - this can effect time critical
  869.           routines like the serial interrupt service routine in RS232.C.
  870.           Only experimentation can determine what the highest usable speed
  871.           is on any given machine and configuration.
  872.  
  873.   >   Interrupts:
  874.           Because machines equipped with COM ports 3 and 4 use hardware
  875.           interrupt lines shared with ports 1 and 2, a problem can arise
  876.           with some hardware.  For example, an internal modem is installed
  877.           as COM1 and you are attempting to use COM3 for some other
  878.           purpose.  Because both ports use interrupt request line IRQ4, if
  879.           the modem board is "holding" IRQ4 inactive, COM3 will never be
  880.           able to signal an interrupt and thus will appear dead.  Most
  881.           serial adapter boards do not behave this way and will "float"
  882.           the interrupt request line when not signaling an interrupt.
  883.           Also, the problem can only occur if software accessing the
  884.           problem board leaves interrupts enabled at the board.
  885.           (Specifically, the signal OUT2 is left active with modem control
  886.           register bit 3.)
  887.  
  888.           If your application installs any of it's own interrupt routines,
  889.           they must re-enable interrupts as soon as possible after entry
  890.           to prevent loss of incoming serial characters.
  891.  
  892.           RS232.C re-prioritizes hardware interrupts to give serial
  893.           interrupts the highest priority.  While this will have no
  894.           noticeable effect with most applications, it should be taken
  895.           into account in those applications which make use of hardware
  896.           interrupts from other sources.
  897.  
  898.   >   Polled vs. interrupt driven output:
  899.           The default method of character transmission by RS232.C uses
  900.           interrupts.  Each time a character is written a character is
  901.           written to the UART's transmit holding register, an interrupt is
  902.           generated by the UART when the transmit holding register becomes
  903.           available for the next character to be sent.  It may be
  904.           desirable under certain circumstances to disable this feature
  905.           and use "polled transmission" instead.  This requires that
  906.           software constantly poll the UART and write the next character
  907.           when the transmit holding register becomes free.  The method
  908.           used is determined at compile time.  If the macro RS_POLLED_XMIT
  909.           is defined, the polling method will be used.  The following line
  910.           placed at the beginning of the application's source code will
  911.           accomplish this:
  912.  
  913.              #DEFINE RS_POLLED_XMIT
  914.  
  915.           The following describes some advantages and disadvantages to
  916.           both methods:
  917.  
  918.           Interrupt driven output:
  919.             Advantages:  This is the more efficient method of output.  No
  920.             CPU time is wasted polling the UART.  Characters may be queued
  921.             for output and the application may go on processing without
  922.             waiting for the characters to actually be sent.
  923.  
  924.             Disadvantages:  Some additional overhead is incurred in the
  925.             interrupt service routine.  At high transmission speeds this
  926.             may cause problems on slower machines or under certain
  927.             circumstances.  Interrupt driven output may not work properly
  928.             with some non-standard hardware.
  929.  
  930.           Polled output:
  931.             Advantages:  This method makes the interrupt service routine
  932.             slightly "leaner" and simplifies some of the code elsewhere
  933.             making the overall code size slightly smaller.  This method
  934.             may prove to be more reliable on some hardware.
  935.  
  936.             Disadvantages:  While the application is sending characters,
  937.             it can do nothing else and no output buffer is used.  This
  938.             method is less efficient for throughput.
  939.  
  940.   >   Flow control and handshaking:
  941.           Flow control is provided for only in respect to stopping and
  942.           starting output as requested by remote equipment.  To utilize
  943.           flow control on remote equipment, the application must monitor
  944.           the conditions requiring flow control (i.e. input buffer free
  945.           space) and take the appropriate action when needed (like sending
  946.           XOFF or dropping a hardware line).
  947.  
  948.           Handshaking is something that is completely arbitrary and the
  949.           only requirement is that the local and remote equipment must
  950.           agree on the protocol.  RS232.C provides a function for
  951.           determining the status of and controlling hardware handshake
  952.           lines but it is up to the application to determine how it should
  953.           be used.
  954.  
  955.   >   Compiling:
  956.           If RS232.C can be simply included (whether by "pasting" it
  957.           directly into an applications source code or with a preprocessor
  958.           "#include" directive) no special compiler considerations are
  959.           needed.  If desired, RS232.C can be split into separate header
  960.           and code files to follow more conventional 'C' conventions.
  961.           This is accomplished by splitting the file where indicated.
  962.           Programs using RS232.C can be compiled and linked from the IDE
  963.           if desired.
  964.  
  965.           Borland's newer compilers have many optimization options and, so
  966.           far, none have caused problems with RS232.C.  One necessity is a
  967.           must when using Turbo C 2.0 or earlier compilers: Stack checking
  968.           must be disabled.  With stack checking enabled in the older
  969.           compilers, stack checking code is generated even in interrupt
  970.           functions.
  971.  
  972.           Any of the memory models can be used with RS232.C - the only
  973.           drawback is the extra function call overhead and/or memory
  974.           access overhead incurred with the large models.  This may
  975.           prevent an application from being able to use the higher baud
  976.           rates on some machines.
  977.  
  978.   >   Other Compilers:
  979.  
  980.           RS232.C will compile and run with other DOS based compilers with
  981.           minor changes.  The following lists types/functions/macros which
  982.           may need attention under compilers other than those produced by
  983.           Borland:
  984.  
  985.               function type interrupt - must take care of saving and
  986.               restoring registers and provide IRET instruction
  987.  
  988.               unsigned char inportb(int portid) /* reads a byte from
  989.                                                    a hardware port */
  990.  
  991.               void outportb(int portid,unsigned char value) /* writes a
  992.                                                     /* byte to a port */
  993.  
  994.               void far *MK_FP(unsigned seg, unsigned ofs) /* takes integer
  995.                                                    segment and offset
  996.                                                    arguments and returns
  997.                                                    far pointer */
  998.  
  999.  
  1000.   >   16550 FIFO mode:
  1001.           The 8250A/B and 16450 UARTs found in most machines contain only
  1002.           a one byte buffer for input and output.  This means that for
  1003.           every byte which is received, an interrupt is generated which
  1004.           invokes a routine to retrieve the incoming byte and store it.
  1005.           This must take place before the next incoming byte has been
  1006.           fully received to avoid loss of data.  The same is true of
  1007.           outgoing data - after each byte being transmitted has been
  1008.           sent, an interrupt is generated to invoke a routine to write the
  1009.           next byte to the transmit register.  In some situations, this is
  1010.           simply too much overhead or the interrupt service routines can
  1011.           not be allowed to react quickly enough to keep up with the data.
  1012.           The more sophisticated 16550 series of UARTs overcome this with
  1013.           the inclusion of 16 byte FIFOs (first-in-first-out-registers)
  1014.           for both input and output.  Software must be able to recognize
  1015.           and enable this feature when it's available, and software
  1016.           determines how it is used.  Code in RS232.C checks for the
  1017.           presence of FIFO capable UARTs and automatically employs them.
  1018.           Outgoing data is written to the UART at 16 bytes per interrupt
  1019.           and incoming data signals generates a receive interrupt after 4
  1020.           bytes have accumulated in the FIFO - though up to 16 bytes can
  1021.           be received before the interrupt service routine is able to
  1022.           respond, without losing any data.  These defaults can be changed
  1023.           by altering the corresponding constants in the function
  1024.           rs_initport (see comments in RS232.C).
  1025.  
  1026.   >   Using More Than 1 COM Port Simultaneously:
  1027.           While RS232.C provides no direct support for simultaneous serial
  1028.           port access, it is easy enough to accomplish.  The solution is
  1029.           to include 2 copies of RS232.C in your source code.  Because all
  1030.           variable and function names in RS232.C begin with 'rs_', this
  1031.           makes it easy.  To allow an application to access 2 ports at
  1032.           once you can do the following:
  1033.  
  1034.                 Create 2 copies of RS232.C renaming them to RS232A.C and
  1035.                 RS232B.C.
  1036.  
  1037.                 Using Borland's built in editor (or any editor capable of
  1038.                 search and replace), edit RS232A.C performing a global
  1039.                 search and replace of the string "rs_" with "rs1_".  Do
  1040.                 the same for "RS_" replacing it with "RS1_".
  1041.  
  1042.                 Do the same thing with RS232B.C, replacing "rs_" with
  1043.                 "rs2_" and "RS_" with "RS2_".
  1044.  
  1045.                 Include both modified copies in the source code for your
  1046.                 application.  This provides 2 complete sets of functions
  1047.                 (the function names now start with "rs1_" or "rs2_",
  1048.                 depending on which port is being accessed) allowing access
  1049.                 to 2 different ports and simultaneous serial port I/O.
  1050.                 While not the most elegant of solutions, it is workable
  1051.                 and RS232.C is small enough so as not to make inclusion of
  1052.                 2 copies a problem. (RS232.C adds about 3400 bytes to an
  1053.                 executable file.)
  1054.  
  1055.           Only certain ports can be used simultaneously.  Because COM1
  1056.           uses the same hardware interrupt as COM3 and COM2 uses the same
  1057.           interrupt as COM4, you will most likely not be able to use COM1
  1058.           with COM3 or COM2 with COM4.  The problem arises due to the
  1059.           design of the hardware - if a UART has its OUT2 hardware line at
  1060.           logic 1 (necessary to enable interrupts), another UART sharing
  1061.           the same interrupt will not be able to signal an interrupt.
  1062.           This is true of any serial communications software which uses
  1063.           interrupts.  A serial mouse driver using COM1 preventing serial
  1064.           I/O on COM3 is one example of how this problem may arise even
  1065.           when using only one port in an application.  One way to get
  1066.           around this problem (other than opening and closing the ports as
  1067.           needed using rs_close) is to turn off OUT2 on the UART which is
  1068.           NOT currently being utilized.  OUT2 is controlled by bit 3 of
  1069.           the modem control register at offset 4 from the UART's base I/O
  1070.           address.  The following is an example which would allow
  1071.           interrupts to occur on COM3 and reenable interrupts on COM1 when
  1072.           finished:
  1073.  
  1074.           outportb(0x3FC,(inportb(0x3FC) & '\xF7'); /* COM1 OUT2 off */
  1075.           outportb(0x3EC,(inportb(0x3EC) | '\x08'); /* COM3 OUT2 on */
  1076.             perform I/O with COM3
  1077.                .     .   .    .
  1078.                .     .   .    .
  1079.                .     .   .    .
  1080.           outportb(0x3EC,(inportb(0x3EC) & '\xF7'); /* COM3 OUT2 off */
  1081.           outportb(0x3FC,(inportb(0x3FC) | '\x08'); /* COM1 OUT2 on */
  1082.              resume I/O with COM1
  1083.